package command;

import condition.Condition;
import elements.Robot;
import exceptions.IllegalCommandException;
import exceptions.IllegalConditionException;
/**
 * A class of composed command representing the while command.
 * 
 * @version	3.0
 * @author 	Lies Tambeur 	r0264469	2Bcwsbbh
 * @author	Eline Vanrykel	r0264543	2Bcwselt
 */
public class While extends ComposedCommand {
	/**
	 * The condition of the While.
	 */
	protected Condition condition;
	/**
	 * The command of the While.
	 */
	protected Command command;
	/**
	 * Returns the condition.
	 * @return	The condition.
	 */
	protected Condition getCondition() {
		return this.condition;
	}
	/**
	 * Returns the command.
	 * @return	The command.
	 */
	protected Command getCommand() {
		return this.command;
	}
	/**
	 * Initialize this new while with the given parameters.
	 * @param 	condition
	 * 			The condition of the new While.
	 * @param 	command
	 * 			The command of the new While.
	 * @post   	The condition of this new While is the
	 *         	same as the given condition.
	 * @post   	The command of this new While is the
	 *         	same as the given command.
	 * @throws 	IllegalConditionException
	 * 			This new While cannot have the given condition.   
	 * @throws 	IllegalCommandException
	 * 			This new While cannot have the given command.   
	 */
	public While(Condition condition, Command command) {
		if(!canHaveAsCondition(condition)){
			throw new IllegalConditionException();
		}
		if(!canHaveAsCommand(command)){
			throw new IllegalCommandException();
		}
		this.condition = condition;
		this.command = command;
	}
	/**
	 * Executes the command as long as the condition is true.
	 */
	@Override
	public void execute(Robot robot) {
		while(this.getCondition().evaluate(robot)){
			this.getCommand().execute(robot);
		}
	}
	
	@Override
	public String toString(){
		return "( while " + this.getCondition().toString() + this.getCommand().toString() + "  )";
	}
	
	@Override
	public boolean equals(Object object){
		if(object == null || this==null){
			return false;
		}
		return this.toString().equals(object.toString());
	}
	
	@Override
	public void setAlreadyExecuted(boolean alreadyExecuted){
		this.alreadyExecuted = alreadyExecuted;
		this.getCommand().setAlreadyExecuted(alreadyExecuted);
	}
	/**
	 * If the next executeSingleStep should start in the command.
	 */
	private boolean inWhile = false;
	
	@Override
	public boolean executeSingleStep(Robot robot) {
		if(!this.isAlreadyExecuted()){
			if(inWhile){
				this.getCommand().executeSingleStep(robot);
				if(this.getCommand().isAlreadyExecuted()){
					this.setAlreadyExecuted(false);
					inWhile=false;
				}
			}
			else{
				if(this.getCondition().evaluate(robot)){
					this.inWhile=true;
					this.getCommand().executeSingleStep(robot);
					if(this.getCommand().isAlreadyExecuted()){
						this.setAlreadyExecuted(false);
						inWhile=false;
					}
				}
				else{
					this.setAlreadyExecuted(true);
					return false;
				}
			}
			return true;
			
		}
		return false;
	}
	
	

}
